package org.abettor.leaf4e.popup.actions;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.abettor.leaf4e.Activator;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.ILog;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbenchPart;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * 执行添加pojo的动作
 * @author shawn
 *
 */
public class AddPojo implements IObjectActionDelegate
{
	private Shell shell;
	private ISelection selection;
	private List<AbstractPojoModal> pojoList;
	private ILog logger = Activator.getDefault().getLog();

	@Override
	public void run(IAction action)
	{
		new PojoDialog(shell).open();
	}

	@Override
	public void selectionChanged(IAction action, ISelection selection)
	{
		this.selection = selection;
	}

	@Override
	public void setActivePart(IAction action, IWorkbenchPart workbenchPart)
	{
		shell = workbenchPart.getSite().getShell();
	}

	/**
	 * pojo数据模型
	 * @author shawn
	 *
	 */
	private abstract class AbstractPojoModal
	{
		public String property;
		public String clazz;
		public String column;
		public boolean nullable;
		@Override
		public int hashCode()
		{
			final int prime = 31;
			int result = 1;
			result = prime * result + getOuterType().hashCode();
			result = prime * result
					+ ((property == null) ? 0 : property.hashCode());
			return result;
		}
		@Override
		public boolean equals(Object obj)
		{
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			AbstractPojoModal other = (AbstractPojoModal) obj;
			if (! getOuterType().equals(other.getOuterType()))
				return false;
			if (property == null)
			{
				if (other.property != null)
					return false;
			}
			else if (! property.equals(other.property))
				return false;
			return true;
		}
		private AddPojo getOuterType()
		{
			return AddPojo.this;
		}
	}

	private class PojoModal extends AbstractPojoModal
	{
		public String type;
		public int length;
	}

	private class PkPojoModal extends PojoModal
	{
		public String generator;
		public Map<String, String> generatorValue;
	}

	private class FkPojoModal extends AbstractPojoModal
	{
		public String inverseName;
	}

	private class PojoDialog extends Dialog
	{
		private boolean success = false;
		private Text pkg;
		private Text name;
		private Text table;
		private String pkgStr;
		private String nameStr;
		private String tableStr;
		private CheckboxTableViewer tableViewer;

		protected PojoDialog(Shell parentShell)
		{
			super(parentShell);
		}

		@Override
		protected Control createDialogArea(Composite parent)
		{
			Composite composite = (Composite) super.createDialogArea(parent);
			composite.getShell().setText("Add pojo");

			GridLayout gridLayout = new GridLayout();
			gridLayout.makeColumnsEqualWidth = false;
			gridLayout.numColumns = 3;
			composite.setLayout(gridLayout);

			GridData gridData = new GridData();
			gridData.grabExcessHorizontalSpace = true;
			gridData.horizontalAlignment = GridData.FILL;
			Label label = new Label(composite, SWT.NONE);
			label.setText("Package:");
			pkg = new Text(composite, SWT.BORDER);
			pkg.setLayoutData(gridData);
			Button browse = new Button(composite, SWT.PUSH);
			browse.setText("Browse");
			browse.addMouseListener(new MouseAdapter()
			{
				private List<String> packages;

				@Override
				public void mouseUp(MouseEvent e)
				{
					//	浏览package
					TreeSelection ts = (TreeSelection) selection;
					IJavaProject project = (IJavaProject) ts.getFirstElement();
					IProject proj = project.getProject();
					InputStream is = null;
					try
					{
						IFile conf = proj.getFile(Activator.PLUGIN_CONF);
						is = conf.getContents();
						Properties prop = new Properties();
						prop.load(is);
						IFolder src = proj.getFolder(prop.getProperty("SRC"));
						packages = new ArrayList<String>();
						travelForlder(src, "");
						new PackageDialog(shell).open();
					}
					catch(Exception ex)
					{
						Status status = new Status(IStatus.WARNING, Activator.PLUGIN_ID, "List packages error", ex);
						logger.log(status);
						MessageDialog.openError(shell, "Error", "List packages error.");
					}
					finally
					{
						if(is != null)
						{
							try
							{
								is.close();
							}
							catch (IOException ioe)
							{
								Status status = new Status(IStatus.WARNING, Activator.PLUGIN_ID, "", ioe);
								logger.log(status);
							}
						}
					}
				}

				private void travelForlder(IFolder parentFolder, String base)
				{
					try
					{
						IResource[] resArray = parentFolder.members();
						for(IResource res : resArray)
						{
							if(res instanceof IFolder)
							{
								IFolder folder = (IFolder) res;
								String name = folder.getName();
								if(base != null && ! base.isEmpty())
								{
									name = base + "." + name;
								}
								packages.add(name);
								travelForlder(folder, name);
							}
						}
					}
					catch (CoreException e)
					{
						Status status = new Status(IStatus.WARNING, Activator.PLUGIN_ID, "Traveling packages error", e);
						logger.log(status);
					}
				}

				class PackageDialog extends Dialog
				{
					private Text pack;
					private org.eclipse.swt.widgets.List list;

					protected PackageDialog(Shell parentShell)
					{
						super(parentShell);
					}

					protected Control createDialogArea(Composite parent)
					{
						Composite composite = (Composite) super.createDialogArea(parent);
						composite.getShell().setText("Browse package");
						GridLayout layout = new GridLayout();
						layout.makeColumnsEqualWidth = false;
						layout.numColumns = 2;
						composite.setLayout(layout);

						GridData gridData = new GridData();
						gridData.grabExcessHorizontalSpace = true;
						gridData.horizontalAlignment = GridData.FILL;
						Label label = new Label(composite, SWT.NONE);
						label.setText("Package:");
						pack = new Text(composite, SWT.BORDER);
						pack.setLayoutData(gridData);
						pack.addModifyListener(new ModifyListener()
						{
							@Override
							public void modifyText(ModifyEvent e)
							{
								String filter = pack.getText();
								List<String> filted = null;
								if(filter == null || filter.isEmpty())
								{
									filted = packages;
								}
								else
								{
									filted = new ArrayList<String>();
									for(String item : packages)
									{
										if(item.startsWith(filter))
										{
											filted.add(item);
										}
									}
								}
								String[] listItems = new String[filted.size()];
								filted.toArray(listItems);
								list.setItems(listItems);
								list.setSelection(new int[0]);
							}
						});

						gridData = new GridData();
						gridData.grabExcessHorizontalSpace = true;
						gridData.horizontalAlignment = GridData.FILL;
						gridData.horizontalSpan = 2;
						gridData.widthHint = 400;
						gridData.heightHint = 300;
						list = new org.eclipse.swt.widgets.List(composite, SWT.V_SCROLL | SWT.BORDER | SWT.SINGLE);
						list.setLayoutData(gridData);
						String[] listItems = new String[packages.size()];
						packages.toArray(listItems);
						list.setItems(listItems);
						list.addSelectionListener(new SelectionListener()
						{
							@Override
							public void widgetSelected(SelectionEvent e)
							{
								int idx = list.getSelectionIndex();
								if(idx >= 0)
								{
									pack.setText(list.getItem(idx));
								}
							}
							
							@Override
							public void widgetDefaultSelected(SelectionEvent e)
							{
							}
						});

						return composite;
					}

					protected void okPressed()
					{
						String p = pack.getText();
						if(p == null || p.trim().isEmpty())
						{
							MessageDialog.openError(shell, "Error", "You must fill in the package name.");
							return;
						}
						if(! packages.contains(p))
						{
							MessageDialog.openError(shell, "Error", "The package you entered dose not exist.");
							return;
						}

						pkg.setText(p);
						super.okPressed();
					}
				}
			});

			gridData = new GridData();
			gridData.grabExcessHorizontalSpace = true;
			gridData.horizontalAlignment = GridData.FILL;
			gridData.horizontalSpan = 2;
			label = new Label(composite, SWT.NONE);
			label.setText("Pojo name");
			name = new Text(composite, SWT.BORDER);
			name.setLayoutData(gridData);

			gridData = new GridData();
			gridData.grabExcessHorizontalSpace = true;
			gridData.horizontalAlignment = GridData.FILL;
			gridData.horizontalSpan = 2;
			label = new Label(composite, SWT.NONE);
			label.setText("Table name");
			table = new Text(composite, SWT.BORDER);
			table.setLayoutData(gridData);

			gridData = new GridData();
			gridData.grabExcessHorizontalSpace = true;
			gridData.horizontalAlignment = GridData.FILL;
			gridData.horizontalSpan = 3;
			gridLayout = new GridLayout();
			gridLayout.makeColumnsEqualWidth = false;
			gridLayout.numColumns = 2;
			Group group = new Group(composite, SWT.NONE);
			group.setText("Mapping");
			group.setLayoutData(gridData);
			group.setLayout(gridLayout);

			gridData = new GridData();
			gridData.grabExcessHorizontalSpace = true;
			gridData.horizontalAlignment = GridData.FILL;
			gridData.heightHint = 300;
			TableViewer tv = new TableViewer(group, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL | SWT.CHECK);
			tableViewer = new CheckboxTableViewer(tv.getTable());
			tableViewer.setContentProvider(new ContentProvider());
			tableViewer.setLabelProvider(new TableLabelProvider());
			Table dataTable = tableViewer.getTable();
			dataTable.setLayoutData(gridData);
			dataTable.setLinesVisible(true);
			dataTable.setHeaderVisible(true);
			TableColumn tc = new TableColumn(dataTable, SWT.NONE);
			tc.setText("");
			tc.setWidth(20);
			tc = new TableColumn(dataTable, SWT.NONE);
			tc.setText("PK");
			tc.setWidth(40);
			tc = new TableColumn(dataTable, SWT.NONE);
			tc.setText("FK");
			tc.setWidth(40);
			tc = new TableColumn(dataTable, SWT.NONE);
			tc.setText("Property");
			tc.setWidth(100);
			tc = new TableColumn(dataTable, SWT.NONE);
			tc.setText("Class");
			tc.setWidth(100);
			tc = new TableColumn(dataTable, SWT.NONE);
			tc.setText("Column");
			tc.setWidth(100);
			tc = new TableColumn(dataTable, SWT.NONE);
			tc.setText("Type");
			tc.setWidth(100);
			tc = new TableColumn(dataTable, SWT.NONE);
			tc.setText("Length");
			tc.setWidth(60);
			tc = new TableColumn(dataTable, SWT.NONE);
			tc.setText("Nullable");
			tc.setWidth(60);

			pojoList = new ArrayList<AbstractPojoModal>();
			PkPojoModal ppm = new PkPojoModal();
			ppm.clazz = "int";
			ppm.column = "n_id";
			ppm.generator = "identity";
			ppm.property = "id";
			ppm.type = "integer";
			pojoList.add(ppm);
			tableViewer.add(new AbstractPojoModal[]{ppm});

			gridLayout = new GridLayout();
			gridLayout.numColumns = 1;
			gridData = new GridData();
			gridData.grabExcessHorizontalSpace = true;
			gridData.horizontalAlignment = GridData.END;
			gridData.grabExcessVerticalSpace = true;
			gridData.verticalAlignment = GridData.CENTER;
			Composite comp = new Composite(group, SWT.NONE);
			comp.setLayout(gridLayout);
			comp.setLayoutData(gridData);

			gridData = new GridData();
			gridData.grabExcessHorizontalSpace = true;
			gridData.horizontalAlignment = GridData.FILL;
			Button btn = new Button(comp, SWT.PUSH);
			btn.setText("Add PK");
			btn.setLayoutData(gridData);
			btn.addMouseListener(new MouseAdapter()
			{
				public void mouseUp(MouseEvent e)
				{
					//	添加主键
					PkDialog pk = new PkDialog(shell);
					if(pk.open() == Dialog.OK)
					{
						PkPojoModal ppm = pk.getPojoModal();
						pojoList.add(ppm);
						tableViewer.add(ppm);
					}
				}

				//	添加主键
				class PkDialog extends Dialog
				{
					private PkPojoModal modal;
					private Text property;
					private Combo clazz;
					private Text column;
					private Combo type;
					private Text length;
					private Combo generator;
					private Composite generatorComp;
					private ScrolledComposite scrolledComp;
					private List<Text> generatorParam = new ArrayList<Text>();
					private List<Text> generatorValue = new ArrayList<Text>();

					protected PkDialog(Shell parentShell)
					{
						super(parentShell);
					}

					protected Control createDialogArea(Composite parent)
					{
						modal = new PkPojoModal();
						Composite composite = (Composite) super.createDialogArea(parent);
						composite.getShell().setText("Add PK");
						GridLayout layout = new GridLayout();
						layout.makeColumnsEqualWidth = false;
						layout.numColumns = 2;
						composite.setLayout(layout);

						GridData gridData = new GridData();
						gridData.grabExcessHorizontalSpace = true;
						gridData.horizontalAlignment = GridData.FILL;
						Label label = new Label(composite, SWT.NONE);
						label.setText("Property:");
						property = new Text(composite, SWT.BORDER);
						property.setLayoutData(gridData);

						gridData = new GridData();
						gridData.grabExcessHorizontalSpace = true;
						gridData.horizontalAlignment = GridData.FILL;
						label = new Label(composite, SWT.NONE);
						label.setText("Class:");
						String[] clazzItems = {"int",
								"short",
								"long",
								"float",
								"double",
								"boolean",
								"byte",
								"char",
								"Integer",
								"Short",
								"Long",
								"Float",
								"Double",
								"Boolean",
								"Byte",
								"Character",
								"String",
								"java.util.Date"};
						clazz = new Combo(composite, SWT.NONE);
						clazz.setLayoutData(gridData);
						clazz.setItems(clazzItems);

						gridData = new GridData();
						gridData.grabExcessHorizontalSpace = true;
						gridData.horizontalAlignment = GridData.FILL;
						label = new Label(composite, SWT.NONE);
						label.setText("Column:");
						column = new Text(composite, SWT.BORDER);
						column.setLayoutData(gridData);

						gridData = new GridData();
						gridData.grabExcessHorizontalSpace = true;
						gridData.horizontalAlignment = GridData.FILL;
						label = new Label(composite, SWT.NONE);
						label.setText("Type:");
						String[] typeItems = {"integer",
								"short",
								"long",
								"float",
								"double",
								"boolean",
								"byte",
								"character",
								"string",
								"timestamp"};
						type = new Combo(composite, SWT.NONE);
						type.setLayoutData(gridData);
						type.setItems(typeItems);

						gridData = new GridData();
						gridData.grabExcessHorizontalSpace = true;
						gridData.horizontalAlignment = GridData.FILL;
						label = new Label(composite, SWT.NONE);
						label.setText("Length:");
						length = new Text(composite, SWT.BORDER);
						length.setLayoutData(gridData);

						gridData = new GridData();
						gridData.grabExcessHorizontalSpace = true;
						gridData.horizontalAlignment = GridData.FILL;
						label = new Label(composite, SWT.NONE);
						label.setText("Generator:");
						String[] generatorItems = {"identity",
								"sequence",
								"native",
								"assigned",
								"uuid.hex",
								"uuid.string",
								"guid",
								"increment",
								"hilo",
								"sequencehilo"};
						generator = new Combo(composite, SWT.NONE);
						generator.setLayoutData(gridData);
						generator.setItems(generatorItems);

						gridData = new GridData();
						gridData.grabExcessHorizontalSpace = true;
						gridData.horizontalAlignment = GridData.FILL;
						gridData.horizontalSpan = 2;
						layout = new GridLayout();
						layout.makeColumnsEqualWidth = false;
						layout.numColumns = 2;
						Composite comp = new Composite(composite, SWT.NONE);
						comp.setLayout(layout);
						comp.setLayoutData(gridData);

						gridData = new GridData();
						gridData.grabExcessHorizontalSpace = true;
						gridData.horizontalAlignment = GridData.FILL;
						layout = new GridLayout();
						layout.makeColumnsEqualWidth = true;
						layout.numColumns = 2;
						Group generatorGroup = new Group(comp, SWT.NONE);
						generatorGroup.setLayout(layout);
						generatorGroup.setLayoutData(gridData);
						generatorGroup.setText("Generator parameter");

						gridData = new GridData();
						gridData.grabExcessHorizontalSpace = true;
						gridData.horizontalAlignment = GridData.BEGINNING;
						label = new Label(generatorGroup, SWT.NONE);
						label.setText("Parameter");
						label.setLayoutData(gridData);

						gridData = new GridData();
						gridData.grabExcessHorizontalSpace = true;
						gridData.horizontalAlignment = GridData.BEGINNING;
						label = new Label(generatorGroup, SWT.NONE);
						label.setText("Value");
						label.setLayoutData(gridData);

						gridData = new GridData();
						gridData.horizontalSpan = 2;
						gridData.grabExcessHorizontalSpace = true;
						gridData.horizontalAlignment = GridData.FILL;
						scrolledComp = new ScrolledComposite(generatorGroup, SWT.V_SCROLL);
						scrolledComp.setLayoutData(gridData);
						scrolledComp.setLayout(new GridLayout());
						scrolledComp.setExpandVertical(true);
						scrolledComp.setMinSize(405, 200);

						gridData = new GridData();
						gridData.grabExcessHorizontalSpace = true;
						gridData.horizontalAlignment = GridData.FILL;
						layout = new GridLayout();
						layout.makeColumnsEqualWidth = true;
						layout.numColumns = 2;
						generatorComp = new Composite(scrolledComp, SWT.NONE);
						generatorComp.setLayoutData(gridData);
						generatorComp.setLayout(layout);
						scrolledComp.setContent(generatorComp);

						gridData = new GridData();
						gridData.grabExcessVerticalSpace = true;
						gridData.verticalAlignment = GridData.CENTER;
						Button addButton = new Button(comp, SWT.PUSH);
						addButton.setLayoutData(gridData);
						addButton.setText("Add");
						addButton.addMouseListener(new MouseAdapter()
						{
							public void mouseUp(MouseEvent e)
							{
								GridData gridData = new GridData();
								gridData.grabExcessHorizontalSpace = true;
								gridData.horizontalAlignment = GridData.FILL;
								Text name = new Text(generatorComp, SWT.BORDER);
								name.setLayoutData(gridData);
								generatorParam.add(name);

								gridData = new GridData();
								gridData.grabExcessHorizontalSpace = true;
								gridData.horizontalAlignment = GridData.FILL;
								Text value = new Text(generatorComp, SWT.BORDER);
								value.setLayoutData(gridData);
								generatorValue.add(value);

								int newLen = generatorComp.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).y;
								generatorComp.setSize(400, newLen);
								scrolledComp.setMinHeight(newLen);
								generatorComp.layout(true);
								scrolledComp.layout(true);
							}
						});

						return composite;
					}

					protected void okPressed()
					{
						modal.property = property.getText();
						if(modal.property == null || modal.property.trim().isEmpty())
						{
							MessageDialog.openError(shell, "Error", "Property must be filled in.");
							return;
						}
						modal.property = modal.property.trim();
						modal.clazz = clazz.getText();
						if(modal.clazz == null || modal.clazz.trim().isEmpty())
						{
							MessageDialog.openError(shell, "Error", "You must choose a class.");
							return;
						}
						modal.clazz = modal.clazz.trim();
						modal.column = column.getText();
						if(modal.column == null || modal.column.trim().isEmpty())
						{
							MessageDialog.openError(shell, "Error", "Column must be filled in.");
							return;
						}
						modal.column = modal.column.trim();
						modal.type = type.getText();
						if(modal.type == null || modal.type.trim().isEmpty())
						{
							MessageDialog.openError(shell, "Error", "You must choose a type.");
							return;
						}
						modal.type = modal.type.trim();
						String len = length.getText();
						if(len != null && ! len.trim().isEmpty())
						{
							try
							{
								modal.length = Integer.parseInt(len.trim());
							}
							catch(Exception e)
							{
								MessageDialog.openError(shell, "Error", "Length must be a numeric.");
								return;
							}
						}
						modal.generator = generator.getText();
						if(modal.generator == null || modal.generator.trim().isEmpty())
						{
							MessageDialog.openError(shell, "Error", "You must choose a generator.");
							return;
						}
						modal.generator = modal.generator.trim();

						Map<String, String> map = new HashMap<String, String>();
						for(int i = 0; i < generatorParam.size(); i ++)
						{
							Text p = generatorParam.get(i);
							String param = p.getText();
							if(param == null || param.trim().isEmpty())
							{
								continue;
							}

							Text v = generatorValue.get(i);
							String value = v.getText();
							map.put(param.trim(), value.trim());
						}
						if(map.size() > 0)
						{
							modal.generatorValue = map;
						}

						super.okPressed();
					}

					public PkPojoModal getPojoModal()
					{
						return modal;
					}
				}
			});

			gridData = new GridData();
			gridData.grabExcessHorizontalSpace = true;
			gridData.horizontalAlignment = GridData.FILL;
			btn = new Button(comp, SWT.PUSH);
			btn.setText("Add FK");
			btn.setLayoutData(gridData);
			btn.addMouseListener(new MouseAdapter()
			{
				public void mouseUp(MouseEvent e)
				{
					//	添加外键
					FkPojoDialog dialog = new FkPojoDialog(shell);
					if(dialog.open() == Dialog.OK)
					{
						FkPojoModal pojo = dialog.getPojoModal();
						pojoList.add(pojo);
						tableViewer.add(pojo);
					}
				}

				class FkPojoDialog extends Dialog
				{
					private FkPojoModal modal;
					private Text property;
					private Text clazz;
					private Text column;
					private Text inverseName;
					private Button disableInverse;
					private Button nullable;

					protected FkPojoDialog(Shell parentShell)
					{
						super(parentShell);
					}

					protected Control createDialogArea(Composite parent)
					{
						modal = new FkPojoModal();
						Composite composite = (Composite) super.createDialogArea(parent);
						composite.getShell().setText("Add FK");
						GridLayout layout = new GridLayout();
						layout.makeColumnsEqualWidth = false;
						layout.numColumns = 3;
						composite.setLayout(layout);

						GridData gridData = new GridData();
						gridData.grabExcessHorizontalSpace = true;
						gridData.horizontalAlignment = GridData.FILL;
						gridData.horizontalSpan = 2;
						Label label = new Label(composite, SWT.NONE);
						label.setText("Property:");
						property = new Text(composite, SWT.BORDER);
						property.setLayoutData(gridData);

						gridData = new GridData();
						gridData.grabExcessHorizontalSpace = true;
						gridData.horizontalAlignment = GridData.FILL;
						gridData.widthHint = 300;
						label = new Label(composite, SWT.NONE);
						label.setText("Class:");
						clazz = new Text(composite, SWT.BORDER);
						clazz.setLayoutData(gridData);
						gridData = new GridData();
						gridData.grabExcessHorizontalSpace = true;
						gridData.horizontalAlignment = GridData.FILL;
						Button browse = new Button(composite, SWT.PUSH);
						browse.setLayoutData(gridData);
						browse.setText("Browse");
						browse.addMouseListener(new MouseAdapter()
						{
							private List<String> modals;

							public void mouseUp(MouseEvent e)
							{
								//	浏览外键pojo类型
								modals = new ArrayList<String>();
								TreeSelection ts = (TreeSelection) selection;
								IJavaProject project = (IJavaProject) ts.getFirstElement();
								IProject proj = project.getProject();
								InputStream is = null;
								InputStream isConf = null;
								try
								{
									IFile conf = proj.getFile(Activator.PLUGIN_CONF);
									isConf = conf.getContents();
									Properties prop = new Properties();
									prop.load(isConf);
									IFile dataSource = proj.getFile(prop.getProperty("WEB_ROOT") + "/" + prop.getProperty("CONTEXT_FOLDER") + "/" + prop.getProperty("DATA_SOURCE_CONTEXT"));
									DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
									dbf.setValidating(false);
									dbf.setFeature("http://xml.org/sax/features/namespaces", false);
									dbf.setFeature("http://xml.org/sax/features/validation", false);
									dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
									dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
									DocumentBuilder builder = dbf.newDocumentBuilder();
									is = dataSource.getContents();
									Document doc = builder.parse(is);
									Element root = doc.getDocumentElement();
									NodeList list = root.getElementsByTagName("property");
									Element listElement = null;
									for(int i = 0; i < list.getLength(); i ++)
									{
										Node node = list.item(i);
										if(node instanceof Element)
										{
											Element property = (Element) node;
											if("mappingResources".equals(property.getAttribute("name")))
											{
												NodeList listNodes = property.getElementsByTagName("list");
												Node listNode = listNodes.item(0);
												if(listNode instanceof Element)
												{
													listElement = (Element) listNode;
													NodeList values = listElement.getElementsByTagName("value");
													for(int n = 0; n < values.getLength(); n ++)
													{
														Element val = (Element) values.item(n);
														String fileStr = val.getTextContent();
														int position = fileStr.indexOf(".hbm.xml");
														String valStr = fileStr.substring(0, position);
														valStr = valStr.replaceAll("/", ".");
														modals.add(valStr);

														//	除了列举父类外，子列也应该被列举出来
														int idx = valStr.lastIndexOf(".");
														String pack = valStr.substring(0, idx);
														IFile f = proj.getFile(prop.getProperty("SRC") + "/" + fileStr);
														travelSubclass(f, pack, modals);
													}

													break;
												}
											}
										}
									}
									if(listElement == null)
									{
										MessageDialog.openError(shell, "Error", "Parse configuration for pojos error.");
										return;
									}
								}
								catch(Exception ex)
								{
									Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Parse data source configuration error", ex);
									logger.log(status);
									MessageDialog.openError(shell, "Error", "Parse data source configuration error.");
									return;
								}
								finally
								{
									if(is != null)
									{
										try
										{
											is.close();
										}
										catch (IOException ex)
										{
											Status status = new Status(IStatus.WARNING, Activator.PLUGIN_ID, "", ex);
											logger.log(status);
										}
									}
									if(isConf != null)
									{
										try
										{
											isConf.close();
										}
										catch (IOException ex)
										{
											Status status = new Status(IStatus.WARNING, Activator.PLUGIN_ID, "", ex);
											logger.log(status);
										}
									}
								}

								Collections.sort(modals, new Comparator<String>()
								{
									@Override
									public int compare(String o1, String o2)
									{
										char[] ch1 = o1.toCharArray();
										char[] ch2 = o2.toCharArray();
										for(int i = 0; i < ch1.length && i < ch2.length; i ++)
										{
											if(ch1[i] != ch2[i])
											{
												return (ch1[i] - ch2[i]) / Math.abs(ch1[i] - ch2[i]);
											}
										}

										return (ch1.length - ch2.length) / Math.abs(ch1.length - ch2.length);
									}
								});
								new BrowseDialog(shell).open();
							}

							//	列举子pojo类
							private void travelSubclass(IFile file, String packageName, List<String> modals)
							{
								InputStream is = null;
								try
								{
									is = file.getContents();
									DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
									dbf.setValidating(false);
									dbf.setFeature("http://xml.org/sax/features/namespaces", false);
									dbf.setFeature("http://xml.org/sax/features/validation", false);
									dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
									dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
									DocumentBuilder builder = dbf.newDocumentBuilder();
									Document doc = builder.parse(is);
									Element root = doc.getDocumentElement();
									NodeList list = root.getElementsByTagName("subclass");
									int len = list.getLength();
									for(int i = 0; i < len; i ++)
									{
										Element e = (Element) list.item(i);
										String val = e.getAttribute("name");
										if(val.contains("."))
										{
											modals.add(val);
										}
										else
										{
											modals.add(packageName + "." + val);
										}
									}
								}
								catch(Exception e)
								{
									Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, "", e);
									logger.log(status);
								}
								finally
								{
									if(is != null)
									{
										try
										{
											is.close();
										}
										catch (IOException e)
										{
											Status status = new Status(IStatus.WARNING, Activator.PLUGIN_ID, "", e);
											logger.log(status);
										}
									}
								}
							}

							class BrowseDialog extends Dialog
							{
								private org.eclipse.swt.widgets.List list;

								protected BrowseDialog(Shell parentShell)
								{
									super(parentShell);
								}

								protected Control createDialogArea(Composite parent)
								{
									Composite composite = (Composite) super.createDialogArea(parent);
									composite.getShell().setText("Browse pojo");
									composite.setLayout(new GridLayout());
									GridData gridData = new GridData();
									gridData.grabExcessHorizontalSpace = true;
									gridData.horizontalAlignment = GridData.FILL;
									gridData.widthHint = 400;
									gridData.heightHint = 300;
									list = new org.eclipse.swt.widgets.List(composite, SWT.V_SCROLL | SWT.BORDER | SWT.SINGLE);
									list.setLayoutData(gridData);
									String[] items = new String[modals.size()];
									modals.toArray(items);
									list.setItems(items);

									return composite;
								}

								protected void okPressed()
								{
									int idx = list.getSelectionIndex();
									if(idx < 0)
									{
										MessageDialog.openError(shell, "Error", "You must select a pojo here.");
										return;
									}

									String val = list.getItem(idx);
									clazz.setText(val);

									super.okPressed();
								}
							}
						});

						gridData = new GridData();
						gridData.grabExcessHorizontalSpace = true;
						gridData.horizontalAlignment = GridData.FILL;
						gridData.horizontalSpan = 2;
						label = new Label(composite, SWT.NONE);
						label.setText("Column:");
						column = new Text(composite, SWT.BORDER);
						column.setLayoutData(gridData);

						gridData = new GridData();
						gridData.grabExcessHorizontalSpace = true;
						gridData.horizontalAlignment = GridData.FILL;
						label = new Label(composite, SWT.NONE);
						label.setText("Inverse name:");
						inverseName = new Text(composite, SWT.BORDER);
						inverseName.setLayoutData(gridData);
						disableInverse = new Button(composite, SWT.CHECK);
						disableInverse.setText("Disable");
						disableInverse.addMouseListener(new MouseAdapter()
						{
							public void mouseUp(MouseEvent e)
							{
								if(disableInverse.getSelection())
								{
									inverseName.setText("");
									inverseName.setEnabled(false);
								}
								else
								{
									inverseName.setEnabled(true);
								}
							}
						});

						gridData = new GridData();
						gridData.grabExcessHorizontalSpace = true;
						gridData.horizontalAlignment = GridData.FILL;
						gridData.horizontalSpan = 3;
						nullable = new Button(composite, SWT.CHECK);
						nullable.setLayoutData(gridData);
						nullable.setText("Nullable");

						return composite;
					}

					protected void okPressed()
					{
						modal.property = property.getText();
						if(modal.property == null || modal.property.trim().isEmpty())
						{
							MessageDialog.openError(shell, "Error", "Property must be filled in.");
							return;
						}
						modal.property = modal.property.trim();
						modal.clazz = clazz.getText();
						if(modal.clazz == null || modal.clazz.trim().isEmpty())
						{
							MessageDialog.openError(shell, "Error", "You must choose a class.");
							return;
						}
						modal.clazz = modal.clazz.trim();
						modal.column = column.getText();
						if(modal.column == null || modal.column.trim().isEmpty())
						{
							MessageDialog.openError(shell, "Error", "Column must be filled in.");
							return;
						}
						modal.column = modal.column.trim();
						modal.inverseName = inverseName.getText();
						if(! disableInverse.getSelection() && (modal.inverseName == null || modal.inverseName.trim().isEmpty()))
						{
							MessageDialog.openError(shell, "Error", "Inverse name must be filled in.");
							return;
						}
						if(disableInverse.getSelection())
						{
							modal.inverseName = null;
						}
						modal.nullable = nullable.getSelection();

						super.okPressed();
					}

					public FkPojoModal getPojoModal()
					{
						return modal;
					}
				}
			});

			gridData = new GridData();
			gridData.grabExcessHorizontalSpace = true;
			gridData.horizontalAlignment = GridData.FILL;
			btn = new Button(comp, SWT.PUSH);
			btn.setText("Add");
			btn.setLayoutData(gridData);
			btn.addMouseListener(new MouseAdapter()
			{
				public void mouseUp(MouseEvent e)
				{
					//	添加普通列
					PropertyDialog pd = new PropertyDialog(shell);
					if(pd.open() == Dialog.OK)
					{
						PojoModal pm = pd.getPojoModal();
						pojoList.add(pm);
						tableViewer.add(pm);
					}
				}

				//	添加属性
				class PropertyDialog extends Dialog
				{
					private PojoModal modal;
					private Text property;
					private Combo clazz;
					private Text column;
					private Combo type;
					private Text length;
					private Button nullable;

					protected PropertyDialog(Shell parentShell)
					{
						super(parentShell);
					}

					protected Control createDialogArea(Composite parent)
					{
						modal = new PojoModal();
						Composite composite = (Composite) super.createDialogArea(parent);
						composite.getShell().setText("Add property");
						GridLayout layout = new GridLayout();
						layout.makeColumnsEqualWidth = false;
						layout.numColumns = 2;
						composite.setLayout(layout);

						GridData gridData = new GridData();
						gridData.grabExcessHorizontalSpace = true;
						gridData.horizontalAlignment = GridData.FILL;
						Label label = new Label(composite, SWT.NONE);
						label.setText("Property:");
						property = new Text(composite, SWT.BORDER);
						property.setLayoutData(gridData);

						gridData = new GridData();
						gridData.grabExcessHorizontalSpace = true;
						gridData.horizontalAlignment = GridData.FILL;
						label = new Label(composite, SWT.NONE);
						label.setText("Class:");
						String[] clazzItems = {"int",
								"short",
								"long",
								"float",
								"double",
								"boolean",
								"byte",
								"char",
								"Integer",
								"Short",
								"Long",
								"Float",
								"Double",
								"Boolean",
								"Byte",
								"Character",
								"String",
								"java.util.Date",
								"java.sql.Clob",
								"java.sql.Blob"};
						clazz = new Combo(composite, SWT.NONE);
						clazz.setLayoutData(gridData);
						clazz.setItems(clazzItems);

						gridData = new GridData();
						gridData.grabExcessHorizontalSpace = true;
						gridData.horizontalAlignment = GridData.FILL;
						label = new Label(composite, SWT.NONE);
						label.setText("Column:");
						column = new Text(composite, SWT.BORDER);
						column.setLayoutData(gridData);

						gridData = new GridData();
						gridData.grabExcessHorizontalSpace = true;
						gridData.horizontalAlignment = GridData.FILL;
						label = new Label(composite, SWT.NONE);
						label.setText("Type:");
						String[] typeItems = {"integer",
								"short",
								"long",
								"float",
								"double",
								"boolean",
								"byte",
								"character",
								"string",
								"timestamp",
								"clob",
								"blob"};
						type = new Combo(composite, SWT.NONE);
						type.setLayoutData(gridData);
						type.setItems(typeItems);

						gridData = new GridData();
						gridData.grabExcessHorizontalSpace = true;
						gridData.horizontalAlignment = GridData.FILL;
						label = new Label(composite, SWT.NONE);
						label.setText("Length:");
						length = new Text(composite, SWT.BORDER);
						length.setLayoutData(gridData);

						gridData = new GridData();
						gridData.grabExcessHorizontalSpace = true;
						gridData.horizontalAlignment = GridData.FILL;
						gridData.horizontalSpan = 2;
						nullable = new Button(composite, SWT.CHECK);
						nullable.setText("Nullable");
						nullable.setLayoutData(gridData);

						return composite;
					}

					protected void okPressed()
					{
						modal.property = property.getText();
						if(modal.property == null || modal.property.trim().isEmpty())
						{
							MessageDialog.openError(shell, "Error", "Property must be filled in.");
							return;
						}
						modal.property = modal.property.trim();
						modal.clazz = clazz.getText();
						if(modal.clazz == null || modal.clazz.trim().isEmpty())
						{
							MessageDialog.openError(shell, "Error", "You must choose a class.");
							return;
						}
						modal.clazz = modal.clazz.trim();
						modal.column = column.getText();
						if(modal.column == null || modal.column.trim().isEmpty())
						{
							MessageDialog.openError(shell, "Error", "Column must be filled in.");
							return;
						}
						modal.column = modal.column.trim();
						modal.type = type.getText();
						if(modal.type == null || modal.type.trim().isEmpty())
						{
							MessageDialog.openError(shell, "Error", "You must choose a type.");
							return;
						}
						modal.type = modal.type.trim();
						String len = length.getText();
						if(len != null && ! len.trim().isEmpty())
						{
							try
							{
								modal.length = Integer.parseInt(len.trim());
							}
							catch(Exception e)
							{
								MessageDialog.openError(shell, "Error", "Length must be a numeric.");
								return;
							}
						}
						modal.nullable = nullable.getSelection();

						super.okPressed();
					}

					public PojoModal getPojoModal()
					{
						return modal;
					}
				}
			});

			gridData = new GridData();
			gridData.grabExcessHorizontalSpace = true;
			gridData.horizontalAlignment = GridData.FILL;
			btn = new Button(comp, SWT.PUSH);
			btn.setText("Remove");
			btn.setLayoutData(gridData);
			btn.addMouseListener(new MouseAdapter()
			{
				public void mouseUp(MouseEvent e)
				{
					//	删除选中的属性
					Object[] apms = tableViewer.getCheckedElements();
					for(Object apm : apms)
					{
						pojoList.remove(apm);
						tableViewer.remove(apm);
					}
				}
			});

			return composite;
		}

		@Override
		protected void okPressed()
		{
			pkgStr = pkg.getText();
			if(pkgStr == null || pkgStr.trim().isEmpty())
			{
				pkgStr = "";
			}
			else
			{
				pkgStr = pkgStr.trim();
			}
			nameStr = name.getText();
			if(nameStr == null || nameStr.trim().isEmpty())
			{
				MessageDialog.openError(shell, "Error", "Pojo name must be filled in.");
				return;
			}
			nameStr = nameStr.trim();
			tableStr = table.getText();
			if(tableStr == null || tableStr.trim().isEmpty())
			{
				MessageDialog.openError(shell, "Error", "Table name must be filled in.");
				return;
			}
			tableStr = tableStr.trim();

			//	有且只有一个主键才行
			int cnt = 0;
			for(AbstractPojoModal apm : pojoList)
			{
				if(apm instanceof PkPojoModal)
				{
					cnt ++;
				}
			}
			if(cnt != 1)
			{
				MessageDialog.openError(shell, "Error", "The single PK must be defined.");
				return;
			}

			IRunnableWithProgress runnable = new IRunnableWithProgress()
			{
				@Override
				public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException
				{
					doIt(monitor);
				}
			};
			try
			{
				new ProgressMonitorDialog(shell).run(true, false, runnable);
			}
			catch(Exception e)
			{
				Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Create pojo error", e);
				logger.log(status);
				MessageDialog.openError(shell, "Error", "Create pojo error.");
				return;
			}

			//	只有完全执行成功才关闭对话框
			if(success)
			{
				super.okPressed();
			}
		}

		//	执行添加pojo的动作
		private void doIt(IProgressMonitor monitor)
		{
			//	遍历POJO列表，创建类和hbm
			TreeSelection ts = (TreeSelection) selection;
			IJavaProject project = (IJavaProject) ts.getFirstElement();
			IProject proj = project.getProject();
			InputStream isConf = null;
			Properties prop = new Properties();
			try
			{
				IFile conf = proj.getFile(Activator.PLUGIN_CONF);
				isConf = conf.getContents();
				prop.load(isConf);
			}
			catch(Exception e)
			{
				Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Reading project configuration error", e);
				logger.log(status);
				MessageDialog.openError(shell, "Error", "Reading project configuration error.");
				return;
			}
			finally
			{
				if(isConf != null)
				{
					try
					{
						isConf.close();
					}
					catch (IOException e)
					{
						Status status = new Status(IStatus.WARNING, Activator.PLUGIN_ID, "", e);
						logger.log(status);
					}
				}
			}

			//	获取工程信息
			try
			{
				String content = "";
				if(pkgStr != null && ! pkgStr.isEmpty())
				{
					content += "package " + pkgStr + ";\n";
				}
				content += "public class " + nameStr + " implements Serializable {\n";
				content += "}\n";
				IPackageFragmentRoot root = project.findPackageFragmentRoot(project.getPath().append(prop.getProperty("SRC")));
				IPackageFragment packageFrag = root.createPackageFragment(pkgStr, false, monitor);
				ICompilationUnit compilation = packageFrag.createCompilationUnit(nameStr + ".java", content, false, monitor);
				compilation.createImport("java.io.Serializable", null, monitor);
				IType beanClass = compilation.findPrimaryType();
				for(AbstractPojoModal pojo : pojoList)
				{
					String clazz = pojo.clazz;
					if(clazz.indexOf(".") >= 0)
					{
						//	对于需要引入包的类型，引用包
						int idx = clazz.lastIndexOf(".");
						String prefix = clazz.substring(0, idx);
						if(! prefix.equals(pkgStr))
						{
							compilation.createImport(clazz, null, monitor);
						}
						clazz = clazz.substring(idx + 1);
					}

					//	加入属性
					String field = "private " + clazz + " " + pojo.property + ";";
					beanClass.createField(field, null, false, monitor);

					//	加入getter和setter
					String first = pojo.property.substring(0, 1);
					String others = pojo.property.substring(1);
					String name = first.toUpperCase() + others;
					String getter = null;
					if(clazz.equalsIgnoreCase("boolean"))
					{
						getter = "public " + clazz + " is" + name + "(){\n";
					}
					else
					{
						getter = "public " + clazz + " get" + name + "(){\n";
					}
					getter += "\treturn " + pojo.property + ";\n";
					getter += "}\n";
					String setter = "public void set" + name + "(" + clazz + " " + pojo.property + "){\n";
					setter += "\tthis." + pojo.property + " = " + pojo.property + ";\n";
					setter += "}\n";
					beanClass.createMethod(getter, null, false, monitor);
					beanClass.createMethod(setter, null, false, monitor);
				}
			}
			catch (Exception e)
			{
				Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Create pojo class error", e);
				logger.log(status);
				MessageDialog.openError(shell, "Error", "Create pojo class file error.");
				return;
			}

			//	创建pojo配置文件
			try
			{
				String xmlContent = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
				xmlContent += "<hibernate-mapping>\n";
				xmlContent += "</hibernate-mapping>";
				ByteArrayInputStream bais = null;
				ByteArrayInputStream baisXml = null;
				ByteArrayOutputStream baos = null;
				try
				{
					bais = new ByteArrayInputStream(xmlContent.getBytes("UTF-8"));
					DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
					dbf.setValidating(false);
					dbf.setFeature("http://xml.org/sax/features/namespaces", false);
					dbf.setFeature("http://xml.org/sax/features/validation", false);
					dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
					dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
					DocumentBuilder builder = dbf.newDocumentBuilder();
					Document doc = builder.parse(bais);
					Element root = doc.getDocumentElement();
					root.setAttribute("package", pkgStr);
					//	创建class标签
					Element clazzElement = doc.createElement("class");
					clazzElement.setAttribute("name", nameStr);
					clazzElement.setAttribute("table", tableStr);
					root.appendChild(clazzElement);
					//	创建主键
					for(AbstractPojoModal apm : pojoList)
					{
						if(apm instanceof PkPojoModal)
						{
							//	id
							PkPojoModal modal = (PkPojoModal) apm;
							Element pk = doc.createElement("id");
							pk.setAttribute("name", modal.property);
							pk.setAttribute("column", modal.column);
							pk.setAttribute("type", modal.type);
							clazzElement.appendChild(pk);

							//	generator
							Element generator = doc.createElement("generator");
							generator.setAttribute("class", modal.generator);
							pk.appendChild(generator);

							if(modal.generatorValue != null && ! modal.generatorValue.isEmpty())
							{
								for(String param : modal.generatorValue.keySet())
								{
									String val = modal.generatorValue.get(param);
									Element paramElement = doc.createElement("param");
									paramElement.setAttribute("name", param);
									paramElement.setTextContent(val);
									generator.appendChild(paramElement);
								}
							}

							break;
						}
					}
					//	设置其它属性
					for(AbstractPojoModal apm : pojoList)
					{
						if(apm instanceof PojoModal && ! (apm instanceof PkPojoModal))
						{
							PojoModal modal = (PojoModal) apm;
							Element element = doc.createElement("property");
							element.setAttribute("name", modal.property);
							element.setAttribute("column", modal.column);
							element.setAttribute("type", modal.type);
							if(modal.length > 0)
							{
								element.setAttribute("length", modal.length + "");
							}
							if(! modal.nullable)
							{
								element.setAttribute("not-null", "true");
							}
							else
							{
								element.setAttribute("not-null", "false");
							}
							clazzElement.appendChild(element);
						}
						else if(apm instanceof FkPojoModal)
						{
							//	处理外键
							FkPojoModal modal = (FkPojoModal) apm;
							if(modal.clazz.indexOf(".") < 0)
							{
								modal.clazz = pkgStr + "." + modal.clazz;
							}
							String clazz = modal.clazz;
							int idx = clazz.lastIndexOf(".");
							String pkgName = clazz.substring(0, idx);
							if(pkgName.equals(pkgStr))
							{
								clazz = clazz.substring(idx + 1);
							}
							Element element = doc.createElement("many-to-one");
							element.setAttribute("name", modal.property);
							element.setAttribute("column", modal.column);
							element.setAttribute("class", clazz);
							element.setAttribute("cascade", "none");
							element.setAttribute("lazy", "proxy");
							if(modal.nullable)
							{
								element.setAttribute("not-null", "false");
							}
							else
							{
								element.setAttribute("not-null", "true");
							}
							clazzElement.appendChild(element);

							//	如果决定增加反向映射，就做如下事情
							if(modal.inverseName != null)
							{
								//	为类添加反向映射属性
								IPackageFragmentRoot fragRoot = project.findPackageFragmentRoot(project.getPath().append(prop.getProperty("SRC")));
								IPackageFragment pf =fragRoot.getPackageFragment(modal.clazz.substring(0, idx));
								ICompilationUnit cu = pf.getCompilationUnit(modal.clazz.substring(idx + 1) + ".java");
								if(! pkgName.equals(pkgStr))
								{
									cu.createImport(pkgStr + "." + nameStr, null, monitor);
								}
								cu.createImport("java.util.Set", null, monitor);
								IType beanClass = cu.findPrimaryType();
								String field = "private Set<" + nameStr + "> " + modal.inverseName + ";";
								beanClass.createField(field, null, false, monitor);
								String first = modal.inverseName.substring(0, 1);
								String others = modal.inverseName.substring(1);
								String name = first.toUpperCase() + others;
								String getter = "public Set<" + nameStr + "> get" + name + "(){\n";
								getter += "\treturn " + modal.inverseName + ";\n";
								getter += "}\n";
								String setter = "public void set" + name + "(Set<" + nameStr + "> " + modal.inverseName + "){\n";
								setter += "\tthis." + modal.inverseName + " = " + modal.inverseName + ";\n";
								setter += "}\n";
								beanClass.createMethod(getter, null, false, monitor);
								beanClass.createMethod(setter, null, false, monitor);

								//	添加反向映射（支持子类）
								ByteArrayOutputStream os = null;
								ByteArrayInputStream is = null;
								InputStream isFile = null;
								try
								{
									String path = prop.getProperty("SRC") + "/" + modal.clazz.replaceAll("\\.", "/") + ".hbm.xml";
									IFile file = proj.getFile(path);
									if(file == null || ! file.exists())
									{
										//	如果不是父类，则依次查找子类
										InputStream conf = null;
										InputStream isHBM = null;
										ByteArrayOutputStream baosHBM = null;
										InputStream baisHBM = null;
										try
										{
											IFile dsFile = proj.getFile(prop.getProperty("WEB_ROOT") + "/" + prop.getProperty("CONTEXT_FOLDER") + "/" + prop.getProperty("DATA_SOURCE_CONTEXT"));
											DocumentBuilder db = dbf.newDocumentBuilder();
											conf = dsFile.getContents();
											Document confDoc = db.parse(conf);
											NodeList nodeList = confDoc.getElementsByTagName("property");
											int len = nodeList.getLength();
											for(int i = 0; i < len; i ++)
											{
												Element propElement = (Element) nodeList.item(i);
												if("mappingResources".endsWith(propElement.getAttribute("name")))
												{
													NodeList files = propElement.getElementsByTagName("value");
													int size = files.getLength();
													for(int j = 0; j < size; j ++)
													{
														Element fileElement = (Element) files.item(j);
														String fileName = fileElement.getTextContent();
														IFile hbmFile = proj.getFile(prop.getProperty("SRC") + "/" + fileName);
														isHBM = hbmFile.getContents();
														DocumentBuilder dbHBM = dbf.newDocumentBuilder();
														Document docHBM = dbHBM.parse(isHBM);
														NodeList subclassList = docHBM.getElementsByTagName("subclass");
														int length = subclassList.getLength();
														boolean found = false;
														for(int k = 0; k < length; k ++)
														{
															Element subclass = (Element) subclassList.item(k);
															String subName = subclass.getAttribute("name");
															if(! subName.contains("."))
															{
																String fullClassName = fileName.replaceAll("/", ".");
																fullClassName = fullClassName.substring(0, fullClassName.length() - ".hbm.xml".length());
																int dotIdx = fullClassName.lastIndexOf(".");
																subName = fullClassName.substring(0, dotIdx + 1) + subName;
															}
															if(modal.clazz.equals(subName))
															{
																//	找到子类，添加反向映射
																Element set = docHBM.createElement("set");
																set.setAttribute("name", modal.inverseName);
																set.setAttribute("table", tableStr);
																set.setAttribute("inverse", "true");
																set.setAttribute("cascade", "save-update, delete");
																NodeList tmpList = subclass.getElementsByTagName("subclass");
																if(tmpList != null && tmpList.getLength() > 0)
																{
																	Node tmp = tmpList.item(0);
																	subclass.insertBefore(set, tmp);
																}
																else
																{
																	subclass.appendChild(set);
																}

																Element key = docHBM.createElement("key");
																key.setAttribute("column", modal.column);
																set.appendChild(key);

																Element mapping = docHBM.createElement("one-to-many");
																String val = nameStr;
																if(! pkgName.equals(pkgStr))
																{
																	val = pkgStr + "." + nameStr;
																}
																mapping.setAttribute("class", val);
																mapping.setAttribute("not-found", "ignore");
																set.appendChild(mapping);

//																保存文件
																TransformerFactory tf= TransformerFactory.newInstance();
																Transformer transformer = tf.newTransformer();
																transformer.setOutputProperty(OutputKeys.METHOD, "xml");
																transformer.setOutputProperty(OutputKeys.INDENT, "yes");
																transformer.setOutputProperty(OutputKeys.STANDALONE, "no");
																transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "-//Hibernate/Hibernate Mapping DTD 3.0//EN");
																transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd");
																DOMSource source = new DOMSource(docHBM);
																baosHBM = new ByteArrayOutputStream();
																StreamResult result = new StreamResult(baosHBM);
																transformer.transform(source, result);
																baisHBM = new ByteArrayInputStream(baosHBM.toByteArray());
																hbmFile.setContents(baisHBM, true, false, monitor);
																found = true;
																break;
															}
														}
														if(found)
														{
															break;
														}
													}

													break;
												}
											}
										}
										catch(Exception e)
										{
											throw e;
										}
										finally
										{
											if(conf != null)
											{
												conf.close();
											}
											if(isHBM != null)
											{
												isHBM.close();
											}
											if(baosHBM != null)
											{
												baosHBM.close();
											}
											if(baisHBM != null)
											{
												baisHBM.close();
											}
										}
									}
									else
									{
										DocumentBuilder db = dbf.newDocumentBuilder();
										isFile = file.getContents();
										Document parentDoc = db.parse(isFile);
										Element rootNode = parentDoc.getDocumentElement();
										NodeList insertPoints = rootNode.getElementsByTagName("class");
										Element insertPoint = (Element) insertPoints.item(0);
										Element set = parentDoc.createElement("set");
										set.setAttribute("name", modal.inverseName);
										set.setAttribute("table", tableStr);
										set.setAttribute("inverse", "true");
										set.setAttribute("cascade", "save-update, delete");
										NodeList tmpList = insertPoint.getElementsByTagName("subclass");
										if(tmpList != null && tmpList.getLength() > 0)
										{
											Node tmp = tmpList.item(0);
											insertPoint.insertBefore(set, tmp);
										}
										else
										{
											insertPoint.appendChild(set);
										}

										Element key = parentDoc.createElement("key");
										key.setAttribute("column", modal.column);
										set.appendChild(key);

										Element mapping = parentDoc.createElement("one-to-many");
										String val = nameStr;
										if(! pkgName.equals(pkgStr))
										{
											val = pkgStr + "." + nameStr;
										}
										mapping.setAttribute("class", val);
										mapping.setAttribute("not-found", "ignore");
										set.appendChild(mapping);

										//	保存文件
										TransformerFactory tf= TransformerFactory.newInstance();
										Transformer transformer = tf.newTransformer();
										transformer.setOutputProperty(OutputKeys.METHOD, "xml");
										transformer.setOutputProperty(OutputKeys.INDENT, "yes");
										transformer.setOutputProperty(OutputKeys.STANDALONE, "no");
										transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "-//Hibernate/Hibernate Mapping DTD 3.0//EN");
										transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd");
										DOMSource source = new DOMSource(parentDoc);
										os = new ByteArrayOutputStream();
										StreamResult result = new StreamResult(os);
										transformer.transform(source, result);
										is = new ByteArrayInputStream(os.toByteArray());
										file.setContents(is, true, false, monitor);
									}
								}
								catch(Exception e)
								{
									throw e;
								}
								finally
								{
									if(is != null)
									{
										is.close();
									}
									if(os != null)
									{
										os.close();
									}
									if(isFile != null)
									{
										isFile.close();
									}
								}
							}
						}
					}

					//	序列化
					TransformerFactory tf= TransformerFactory.newInstance();
					Transformer transformer = tf.newTransformer();
					transformer.setOutputProperty(OutputKeys.METHOD, "xml");
					transformer.setOutputProperty(OutputKeys.INDENT, "yes");
					transformer.setOutputProperty(OutputKeys.STANDALONE, "no");
					transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "-//Hibernate/Hibernate Mapping DTD 3.0//EN");
					transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd");
					DOMSource source = new DOMSource(doc);
					baos = new ByteArrayOutputStream();
					StreamResult result = new StreamResult(baos);
					transformer.transform(source, result);
					baisXml = new ByteArrayInputStream(baos.toByteArray());
					String folder = prop.getProperty("SRC") + "/" + pkgStr.replaceAll("\\.", "/");
					if(! folder.endsWith("/"))
					{
						folder += "/";
					}
					IFile xml = proj.getFile(folder + nameStr + ".hbm.xml");
					if(! xml.exists())
					{
						xml.create(baisXml, false, monitor);
					}
				}
				catch(Exception e)
				{
					throw e;
				}
				finally
				{
					if(bais != null)
					{
						bais.close();
					}
					if(baos != null)
					{
						baos.close();
					}
					if(baisXml != null)
					{
						baisXml.close();
					}
				}
			}
			catch(Exception e)
			{
				Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Create pojo mapping file error", e);
				logger.log(status);
				MessageDialog.openError(shell, "Error", "Create pojo mapping file error.");
				return;
			}

			//	添加到DataSource
			try
			{
				String path = pkgStr.replaceAll("\\.", "/");
				if(! path.endsWith("/"))
				{
					path += "/";
				}
				if(path.startsWith("/"))
				{
					path = path.substring(1);
				}
				path += nameStr + ".hbm.xml";
				IFile dataSource = proj.getFile(prop.getProperty("WEB_ROOT") + "/" + prop.getProperty("CONTEXT_FOLDER") + "/" + prop.getProperty("DATA_SOURCE_CONTEXT"));
				if(! dataSource.exists())
				{
					MessageDialog.openError(shell, "Error", "No data source configuration found.");
					return;
				}
				DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
				factory.setValidating(false);
				factory.setFeature("http://xml.org/sax/features/namespaces", false);
				factory.setFeature("http://xml.org/sax/features/validation", false);
				factory.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
				factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
				DocumentBuilder builder = factory.newDocumentBuilder();
				Document doc = null;
				InputStream dataIs = null;
				try
				{
					dataIs = dataSource.getContents();
					doc = builder.parse(dataIs);
				}
				catch(Exception e)
				{
					throw e;
				}
				finally
				{
					if(dataIs != null)
					{
						dataIs.close();
					}
				}
				Element root = doc.getDocumentElement();
				NodeList list = root.getElementsByTagName("property");
				int cnt = 0;
				for(int i = 0; i < list.getLength(); i ++)
				{
					Node node = list.item(i);
					if(node instanceof Element)
					{
						Element property = (Element) node;
						if("mappingResources".equals(property.getAttribute("name")))
						{
							NodeList listNodes = property.getElementsByTagName("list");
							Node listNode = listNodes.item(0);
							if(listNode instanceof Element)
							{
								Element target = (Element) listNode;
								Element pojoElement = doc.createElement("value");
								pojoElement.setTextContent(path);
								target.appendChild(pojoElement);
								cnt ++;
								break;
							}
						}
					}
				}
				if(cnt == 0)
				{
					MessageDialog.openError(shell, "Error", "No inserting point found.");
					return;
				}
				//	序列化
				ByteArrayOutputStream baos = null;
				ByteArrayInputStream baisXml = null;
				try
				{
					TransformerFactory tf= TransformerFactory.newInstance();
					Transformer transformer = tf.newTransformer();
					transformer.setOutputProperty(OutputKeys.METHOD, "xml");
					transformer.setOutputProperty(OutputKeys.INDENT, "yes");
					transformer.setOutputProperty(OutputKeys.STANDALONE, "no");
					DOMSource source = new DOMSource(doc);
					baos = new ByteArrayOutputStream();
					StreamResult result = new StreamResult(baos);
					transformer.transform(source, result);
					baisXml = new ByteArrayInputStream(baos.toByteArray());
					dataSource.setContents(baisXml, true, false, monitor);
				}
				catch(Exception e)
				{
					throw e;
				}
				finally
				{
					if(baos != null)
					{
						baos.close();
					}
					if(baisXml != null)
					{
						baisXml.close();
					}
				}
			}
			catch(Exception e)
			{
				Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Error when inserting pojo mapping into data source", e);
				logger.log(status);
				MessageDialog.openError(shell, "Error", "Error when inserting pojo mapping into data source.");
			}

			success = true;
		}
	}

	private class ContentProvider implements IStructuredContentProvider
	{
		@Override
		public void dispose()
		{
		}

		@Override
		public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
		{
		}

		@SuppressWarnings("unchecked")
		@Override
		public Object[] getElements(Object inputElement)
		{
			if (inputElement instanceof List)
			{
				List<Object> list = (List<Object>) inputElement;
				Object[] val = new Object[list.size()];
				list.toArray(val);
				return val;
			}
			else
			{
				return new Object[0];
			}
		}
	}

	private class TableLabelProvider extends LabelProvider implements ITableLabelProvider
	{
		@Override
		public Image getColumnImage(Object element, int index)
		{
			return null;
		}

		@Override
		public String getColumnText(Object element, int index)
		{
			if (element instanceof AbstractPojoModal)
			{
				AbstractPojoModal modal = (AbstractPojoModal) element;
				switch(index)
				{
				case 0:
					return "";
				case 1:
					if(modal instanceof PkPojoModal)
					{
						return "Y";
					}
					return "N";
				case 2:
					if(modal instanceof FkPojoModal)
					{
						return "Y";
					}
					return "N";
				case 3:
					return modal.property;
				case 4:
					return modal.clazz;
				case 5:
					return modal.column;
				case 6:
					if(modal instanceof PojoModal)
					{
						PojoModal pm = (PojoModal) modal;
						return pm.type;
					}
					return "-";
				case 7:
					if(modal instanceof PojoModal)
					{
						PojoModal pm = (PojoModal) modal;
						return pm.length + "";
					}
					return "-";
				case 8:
					return modal.nullable ? "Y" : "N";
				}
			}

			return null;
		}
	}
}
